﻿#pragma once
#include <opencv2/core/core.hpp>
#include <stdint.h>

class Census
{
public:
	struct Parameters
	{
		///\brief census变换的x窗口大小，需要是奇数
		int window_x;

		///\brief census变换的y窗口大小，需要是奇数
		int window_y;

		/**\brief census变换后影像的数据类型
		*
		*对于9x7窗口，需要64bit，为了方便SSE实现，目前只支持这个窗口
		*/
		int output_type;
		Parameters()
		{
			window_x = 9;
			window_y = 7;
			output_type = 64;
		}
	};
public:
	Census(const Parameters& param) { param_ = param; }
	Census(){}
	~Census(){};

	/*************************************************************************/
	/**
	* \brief		对影像进行census变换 ,采用SSE实现
	* \param[in]	src 输入影像 
	* \param[out]	dst 输出影像,输出影像的格式为CV_8UC8
	*
	*需要注意的是，在影像边缘，会留下window_x / 2, window_y / 2的黑边，支持的影像类型，
	*包括CV_8UC1, CV_16SC1, CV_32FC1
	*/ 
	/*************************************************************************/
	void operator()(const cv::Mat& src, cv::Mat& dst);
	/*************************************************************************/
	/**
	* \brief		线性实现 
	* \param[in]	src 输入影像
	* \param[out]	dst 输出影像，每个像素为8个BYTE
	*/ 
	/*************************************************************************/
	void serial(const cv::Mat& src, cv::Mat& dst);
protected:

	///\brief 对于8bit影像
	void census_8u(const cv::Mat& src, cv::Mat& dst);
	void census_8u_serial(const cv::Mat& src, cv::Mat& dst);

	///\brief 对于16bit影像
	void census_16u(const cv::Mat& src, cv::Mat& dst);
	void census_16u_serial(const cv::Mat& src, cv::Mat& dst);

	///\brief 对于32bit的float影像
	void census_32f(const cv::Mat& src, cv::Mat& dst);
	void census_32f_serial(const cv::Mat& src, cv::Mat& dst);


	/*************************************************************************/
	/**
	* \brief		Interleaving 从连续的8个m128i中，进行操作
	* \param[in]	src 输入影像，内存对每个像素是分散的，每个m128i中只存8bit
	* \param[out]	dst 输出影像，内存对每个像素是连续的，每个m128i存2个像素
	*
	*由于对于8bit影像，一次性会读取16个像素，进行大小比较，所以一个m128i中，只能
	*记录一个像素进行census变换后的8bit值
	*/ 
	/*************************************************************************/
	void store_8u64b(__m128i* src, __m128i* dst);

	/*************************************************************************/
	/**
	* \brief		Interleaving 从连续的4个m128i中，进行操作 
	* \param[in]	src 输入影像，内存对每个像素是分散的，每个m128i中只存16bit
	* \param[out]	dst 输出影像，内存对每个像素是连续的，每个m128i存2个像素
	*/ 
	/*************************************************************************/
	void store_16u64b(__m128i* src, __m128i* dst);
	/*************************************************************************/
	/**
	* \brief		Interleaving 从连续的2个m128i中，进行操作
	* \param[in]	src 输入影像，内存对每个像素是分散的，每个m128i中只存32bit
	* \param[out]	dst 输出影像，内存对每个像素是连续的，每个m128i存2个像素
	*/
	/*************************************************************************/

	void store_32u64b(__m128i* src, __m128i* dst);

	Parameters param_;
};
